home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 April: Mac OS SDK / Dev.CD Apr 96 SDK / Dev.CD Apr 96 SDK1.toast / Development Kits (Disc 1) / OpenDoc / Documentation / Tech Notes & Articles / Recipes / Imaging & Layout / QuickDraw GX and OpenDoc < prev    next >
Encoding:
Text File  |  1995-04-24  |  8.8 KB  |  88 lines  |  [TEXT/ttxt]

  1. OpenDoc™ Recipes
  2.  
  3. QuickDraw GX and OpenDoc
  4. by the OpenDoc Engineering Team
  5. April 17, 1995
  6.  
  7.  
  8. © 1995  Apple Computer, Inc. All Rights Reserved.
  9. Apple, the Apple logo, and Macintosh are registered trademarks of Apple Computer, Inc.
  10. Mac and OpenDoc are trademarks of Apple Computer, Inc.
  11.  
  12.  
  13. Introduction
  14.  
  15. OpenDoc and the QuickDraw GX imaging system work together very well. They have very similar models of how drawing happens, and in fact using GX for imaging makes it a lot easier to support OpenDoc features such as multiple views of content (multiple frames and facets) and geometric transformations such as scaling, rotation and perspective.
  16.  
  17. Getting to this blessed state takes a little bit of work, however. The trick is in synchronizing OpenDoc's ODFrame and ODFacet objects with the corresponding gxTransform and gxViewport objects. This means creating a matching GX object for each of the OpenDoc objects, and updating the properties of the GX objects whenever the OpenDoc objects change. Fortunately, OpenDoc notifies your editor whenever frames and facets are created, deleted or modified, so this is not difficult to do with a bit of boilerplate code.
  18.  
  19.  
  20. Theory of Operation
  21.  
  22. An ODFrame object represents an area of content in the document's coordinate space. A part may have multiple display frames. Its properties that concern us when working with QuickDraw GX are its used shape, which describes the area occupied by the shape in the part's coordinate system, and its internal transform, which maps the part's coordinate system to its container's coordinate system (thus describing how the part's content is offset, scaled, etc. within its frame.)
  23.  
  24. In this regard, an ODFrame is very much like a gxTransform object. (Don't be confused by terminology; a gxTransform is not the same as an ODTransform, which is more like a gxMapping or transformation matrix.) A gxTransform has a clip, which describes the area within which drawing occurs, and a mapping, which maps shapes' coordinate systems to the coordinate system of the transform's viewPort.
  25.  
  26. An ODFacet object represents a place in a window or print job where a frame (or portion of one) is being displayed. There may be any number of facets (typically only zero or one) associated with a single ODFrame. The facet properties that concern us when working with QuickDraw GX are its clip shape, which describes the area that is currently visible, and its external transform, which maps the clip shape to its container's coordinate system (thus describing how the facet itself is offset, scaled, etc. within its containing facet.)
  27.  
  28. An ODFacet is very much like a gxViewPort object. A gxViewPort is generally associated with a window or print job into which it draws. A gxViewPort also has a clip, which describes the area of the output device in which drawing can occur, and a mapping, which maps the transform's coordinate system to that of the output device.
  29.  
  30. In short, it's necessary to associate a gxTransform with each display frame, and a gxViewPort with each facet. Each frame's used shape is synchronized with its gxTransform's clip, and its internal transform with its gxTransform's mapping. Each facet's clip shape is synchronized with its gxViewPort's clip, and its external transform with its gxViewPort's mapping. (How to implement the “association” between these objects is up to you. The most straightforward way is to store references to the GX objects in the OD objects' PartInfo properties, or in structs/objects that are pointed to by the PartInfo. If you need to store reverse associations from GX to OD, you could attach custom tags to the GX objects containing references to the OD objects.)
  31.  
  32. One could be extra fancy and replicate the document's entire hierarchy of frames and facets as a hierarchy of gxTransforms and gxViewPorts. However, this doesn't work well in practice because you only own one particular part of the hierarchy, and don't have access to the GX objects being used by your parent frames and facets (which may not even be using GX at all.) Therefore, it works better if you make your GX structures flat and attach your viewPorts directly to the window's root viewPort. This means you'll need to use the facet's content transform, which concatenates its external transform and those of its parent facets all the way to the window. (In other words, it maps frame coordinates to window coordinates.)
  33.  
  34.  
  35. Implementation
  36.  
  37. The descriptions in this recipe refer to the sample “GXPart” which is included with the OpenDoc developer release in the folder "Sample Parts: Unsupported Samples: GXPart:". This part is based on the standard SamplePart; the GX-specific additions are delimited with comments containing the keyword “GXSPECIFIC” so you can easily search for them. The good stuff is in the files GXPart.cpp and GXPartGXStuff.cpp; you may want fo follow along in those files since the code itself will not be repeated here.
  38.  
  39. GXPart, like SamplePart, uses a simple C++ class called CFrameInfo, an instance of which which is associated with each frame by storing a pointer to it in the frame's partInfo property. In GXPart this class has been extended to store two additional pieces of information: the gxTransform associated with the frame, and a gxPicture which is the group of shapes to be drawn in that frame. (A real part would probably have a more complex data format than a simple gxPicture.) This structure is defined in the file GXPartUtils.h.
  40.  
  41.  
  42. Checking Whether GX is installed
  43. When your editor is first loaded you should check whether QuickDraw GX is installed, by calling Gestalt and also testing the address of any GX routine to see if it's NULL. The CFM initialization routine of your library is a good place to do this. Store the result in a boolean variable for later use.
  44. Later on, before doing a GX operation, test the boolean. If GX is not installed you should of course bypass any GX specific code. When displaying, just fill your frame with gray or something similar. You might want to display in the frame a notice that the part cannot display its content because GX is not installed.
  45.  
  46.  
  47. Associating a gxTransform with an ODFrame
  48.  
  49. When a frame is added or reconnected, we must create a new gxTransform, remove any default viewPorts attached to it (we'll attach our own when facets are added) and update its properties to match those of the frame.
  50. This is illustrated in GXPart by the MakeFrameTransform function which is called from the DisplayFrameAdded and DisplayFrameConnected methods.
  51.  
  52.  
  53. Updating the frame's associated gxTransform
  54.  
  55. When a frame's used shape or internal transform change, you need to update the the clip or map of the corresponding gxTransform.  This is illustrated in GXPart by the UpdateFrameTransform function.
  56.  
  57. Since the part is responsible for maintaining its own used shape and internal transform, there are no methods that notify you when these change. When you yourself change them, however, you should be sure to update the clip and map of the associated gxTransform.
  58.  
  59.  
  60. Deleting the frame's associated gxTransform
  61.  
  62. When a frame is closed or removed, it's time to delete the associated gxTransform.  This is illustrated in GXPart by the DisposeFrameTransform function which is called from the DisplayFrameClosed and DisplayFrameRemoved methods.
  63.  
  64.  
  65. Associating a gxViewPort with an ODFacet
  66.  
  67. When a facet is attached to a frame, we must create a new gxViewPort as a child of the facet's canvas' viewPort, update its properties to match those of the facet, and add the viewPort to the viewPort list of the corresponding frame's gxTransform.
  68. This is illustrated in GXPart by the MakeFacetViewPort function which is called from the FacetAdded method.
  69.  
  70.  
  71. Updating the facet's associated gxViewPort
  72.  
  73. When a facet's clip shape or external transform change, you need to update the the clip or map of the corresponding gxViewPort.  This is illustrated in GXPart by the UpdateFacetViewPort function which is called from the GeometryChanged method.
  74.  
  75. When a facet's canvas changes, you need to delete the associated gxViewPort and create another one on the root viewPort of the new canvas. This is illustrated by the CanvasChanged method of GXPart.
  76.  
  77.  
  78. Deleting the facet's associated gxViewPort
  79.  
  80. When a facet is removed, it's time to delete the associated gxViewPort, after detaching it from the frame's gxTransform's viewPort list.  This is illustrated in GXPart by the DisposeFacetViewPort function which is called from the FacetRemoved method.
  81.  
  82.  
  83. Drawing your content
  84.  
  85. Drawing is easy. Your content consists of GX shape objects, each of which is associated with its frame's gxTransform. To draw, just call GXDrawShape on the shape object(s).
  86.  
  87. This assumes that each frame has different shapes; if multiple frames are sharing the same content, you just need to make sure the shape(s) are attached to the right frame before drawing it. You do this by calling GXSetShapeTransform, passing in the shape and the gxTransform associated with the frame.
  88.